/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package ms.jasim.model.event.impl;

import ms.jasim.framework.IJasimAppContext;
import ms.jasim.framework.SolutionSimulator.SimulatedAction;
import ms.jasim.framework.SolutionSimulator.SimulatorArg;
import ms.jasim.model.Actor;
import ms.jasim.model.Goal;
import ms.jasim.model.ModelPackage;
import ms.jasim.model.event.ActionRelativeTime;
import ms.jasim.model.event.ActionType;
import ms.jasim.model.event.EventPackage;
import ms.jasim.model.impl.ModelObjectImpl;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Action Relative Time</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link ms.jasim.model.event.impl.ActionRelativeTimeImpl#getTimeOffset <em>Time Offset</em>}</li>
 *   <li>{@link ms.jasim.model.event.impl.ActionRelativeTimeImpl#getAction <em>Action</em>}</li>
 *   <li>{@link ms.jasim.model.event.impl.ActionRelativeTimeImpl#getActor <em>Actor</em>}</li>
 *   <li>{@link ms.jasim.model.event.impl.ActionRelativeTimeImpl#getGoal <em>Goal</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class ActionRelativeTimeImpl extends ModelObjectImpl implements ActionRelativeTime {
	/**
	 * The default value of the '{@link #getTimeOffset() <em>Time Offset</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getTimeOffset()
	 * @generated
	 * @ordered
	 */
	protected static final int TIME_OFFSET_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getTimeOffset() <em>Time Offset</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getTimeOffset()
	 * @generated
	 * @ordered
	 */
	protected int timeOffset = TIME_OFFSET_EDEFAULT;

	/**
	 * The default value of the '{@link #getAction() <em>Action</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getAction()
	 * @generated
	 * @ordered
	 */
	protected static final ActionType ACTION_EDEFAULT = ActionType.SATISFIES;

	/**
	 * The cached value of the '{@link #getAction() <em>Action</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getAction()
	 * @generated
	 * @ordered
	 */
	protected ActionType action = ACTION_EDEFAULT;

	/**
	 * The cached value of the '{@link #getActor() <em>Actor</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getActor()
	 * @generated
	 * @ordered
	 */
	protected Actor actor;

	/**
	 * The cached value of the '{@link #getGoal() <em>Goal</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getGoal()
	 * @generated
	 * @ordered
	 */
	protected Goal goal;

	private SimulatedAction influentAction;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected ActionRelativeTimeImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return EventPackage.Literals.ACTION_RELATIVE_TIME;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getTimeOffset() {
		return timeOffset;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setTimeOffset(int newTimeOffset) {
		int oldTimeOffset = timeOffset;
		timeOffset = newTimeOffset;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, EventPackage.ACTION_RELATIVE_TIME__TIME_OFFSET, oldTimeOffset, timeOffset));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public ActionType getAction() {
		return action;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setAction(ActionType newAction) {
		ActionType oldAction = action;
		action = newAction == null ? ACTION_EDEFAULT : newAction;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, EventPackage.ACTION_RELATIVE_TIME__ACTION, oldAction, action));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Actor getActor() {
		if (actor != null && actor.eIsProxy()) {
			InternalEObject oldActor = (InternalEObject)actor;
			actor = (Actor)eResolveProxy(oldActor);
			if (actor != oldActor) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, EventPackage.ACTION_RELATIVE_TIME__ACTOR, oldActor, actor));
			}
		}
		return actor;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Actor basicGetActor() {
		return actor;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setActor(Actor newActor) {
		Actor oldActor = actor;
		actor = newActor;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, EventPackage.ACTION_RELATIVE_TIME__ACTOR, oldActor, actor));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Goal getGoal() {
		if (goal != null && goal.eIsProxy()) {
			InternalEObject oldGoal = (InternalEObject)goal;
			goal = (Goal)eResolveProxy(oldGoal);
			if (goal != oldGoal) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, EventPackage.ACTION_RELATIVE_TIME__GOAL, oldGoal, goal));
			}
		}
		return goal;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Goal basicGetGoal() {
		return goal;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setGoal(Goal newGoal) {
		Goal oldGoal = goal;
		goal = newGoal;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, EventPackage.ACTION_RELATIVE_TIME__GOAL, oldGoal, goal));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case EventPackage.ACTION_RELATIVE_TIME__TIME_OFFSET:
				return getTimeOffset();
			case EventPackage.ACTION_RELATIVE_TIME__ACTION:
				return getAction();
			case EventPackage.ACTION_RELATIVE_TIME__ACTOR:
				if (resolve) return getActor();
				return basicGetActor();
			case EventPackage.ACTION_RELATIVE_TIME__GOAL:
				if (resolve) return getGoal();
				return basicGetGoal();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case EventPackage.ACTION_RELATIVE_TIME__TIME_OFFSET:
				setTimeOffset((Integer)newValue);
				return;
			case EventPackage.ACTION_RELATIVE_TIME__ACTION:
				setAction((ActionType)newValue);
				return;
			case EventPackage.ACTION_RELATIVE_TIME__ACTOR:
				setActor((Actor)newValue);
				return;
			case EventPackage.ACTION_RELATIVE_TIME__GOAL:
				setGoal((Goal)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case EventPackage.ACTION_RELATIVE_TIME__TIME_OFFSET:
				setTimeOffset(TIME_OFFSET_EDEFAULT);
				return;
			case EventPackage.ACTION_RELATIVE_TIME__ACTION:
				setAction(ACTION_EDEFAULT);
				return;
			case EventPackage.ACTION_RELATIVE_TIME__ACTOR:
				setActor((Actor)null);
				return;
			case EventPackage.ACTION_RELATIVE_TIME__GOAL:
				setGoal((Goal)null);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case EventPackage.ACTION_RELATIVE_TIME__TIME_OFFSET:
				return timeOffset != TIME_OFFSET_EDEFAULT;
			case EventPackage.ACTION_RELATIVE_TIME__ACTION:
				return action != ACTION_EDEFAULT;
			case EventPackage.ACTION_RELATIVE_TIME__ACTOR:
				return actor != null;
			case EventPackage.ACTION_RELATIVE_TIME__GOAL:
				return goal != null;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public String toString() {
		if (eIsProxy()) return super.toString();

		StringBuffer result = new StringBuffer(super.toString());
		result.append(" (TimeOffset: ");
		result.append(timeOffset);
		result.append(", Action: ");
		result.append(action);
		result.append(')');
		return result.toString();
	}

	
	@Override
	public boolean conditionMatch(IJasimAppContext context, SimulatorArg arg) {
		//IEventSimulationInfoProvider info = context.getService(IEventSimulationInfoProvider.class);
		//JasimModel model = context.getService(JasimModel.class);
		
		for (SimulatedAction act: arg.getSimulator().getHistory()) {
			boolean sameAgent = getActor() == null ||  act.getAgent().getName().equalsIgnoreCase(getActor().getName());
			boolean sameGoal = getGoal() == null ||  act.getGoal().getName().equalsIgnoreCase(getGoal().getName());
			boolean sameFuntor = act.getAssociateAction().getFunctor().toString().equalsIgnoreCase(getAction().getName());
			
			if (sameAgent && sameGoal && sameFuntor && act.getStart() + getTimeOffset() == arg.getTime()) {
				this.influentAction = act;
				//if (info != null && model != null)
				//	info.setData(model.getActors().get(act.getAgent().getName()));
				return true;
			}
		}
		
		return false;
	}

	@Override
	public Object getValue(String name) {
		if (influentAction != null)
			if ("actor".equalsIgnoreCase(name))
				return influentAction.getAgent().getName();
			else if ("goal".equalsIgnoreCase(name))
				return influentAction.getGoal();
		return null;
	}

	@Override
	public boolean hasValue(String name) {
		if (influentAction  != null && "ACTOR;GOAL;".indexOf(name.toUpperCase() + ";") >= 0) return true;
		return false;
	}

	@Override
	public void setValue(String name, Object value) {
		
	}

} //ActionRelativeTimeImpl
